package com.hmjk.health.zxing.decoding;

import java.util.Hashtable;
import java.util.Vector;

import com.hmjk.health.zxing.camera.CameraManager;
import com.hmjk.health.zxing.camera.PlanarYUVLuminanceSource;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.ReaderException;
import com.google.zxing.Result;
import com.google.zxing.ResultPointCallback;
import com.google.zxing.common.HybridBinarizer;

import android.graphics.Rect;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

public class QRScanDecoder {
	private final String TAG = QRScanDecoder.class.getSimpleName();
	public static final int MSG_DECODE_IDLE_LONGTIME = 710;
	public static final int MSG_DECODE_OK = 711;
	public static final int MSG_DECODE_FAIL = 712;
	public static final int MSG_AUTO_FOCUS = 713;
	
	
	private Handler uihandler;
	private CameraManager cm;
	private Runnable mProcessor;
	private MultiFormatReader mReader;
	
	public QRScanDecoder(CameraManager manager, ResultPointCallback rpcallback, Handler uihandler){
		this.uihandler = uihandler;
		cm = manager;
		mProcessor = null;
		mReader = new MultiFormatReader();
		Hashtable<DecodeHintType, Object> hint = new Hashtable<DecodeHintType, Object>(3);
		Vector<BarcodeFormat> decodeFormats = new Vector<BarcodeFormat>();
		decodeFormats.addAll(DecodeFormatManager.ONE_D_FORMATS);
		decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS);
		decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS);
		
		hint.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats);
		hint.put(DecodeHintType.NEED_RESULT_POINT_CALLBACK,rpcallback);
		
		mReader.setHints(hint);
	}
	
	public boolean isIdle(){
		return (mProcessor == null);
	}
	
	public void quit(){
		uihandler = null;
		mProcessor = null;
	}
	
	public boolean process(final byte[] data, final int w, final int h){
		if(mProcessor != null)
			return false;
		
		mProcessor = new Runnable(){

			@Override
			public void run() {
				Result rawResult = null;
				Rect rect = cm.getFramingRectInPreview();
				byte[] rotate = new byte[data.length];
				for(int y = 0; y < h; y++){
					for(int x = 0; x < w; x++){
						rotate[x * h + h - y - 1] = data[x + y * w];
					}
				}
				int rotatew = h;
				int rotateh = w;
				
				PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(rotate, rotatew, rotateh, rect.left, rect.top,rect.width(), rect.height());
				BinaryBitmap bmp = new BinaryBitmap(new HybridBinarizer(source));
				try{
					rawResult = mReader.decodeWithState(bmp);
				}catch(ReaderException e){
					e.printStackTrace();
				}finally{
					mReader.reset();
				}
				if(uihandler != null){
					if(rawResult != null){
						Log.d(TAG, "decode ok");
						Message m = uihandler.obtainMessage(MSG_DECODE_OK, rawResult);
						//Bundle b = new Bundle();
						//b.putParcelable("QR_BITMAP", source.renderCroppedGreyscaleBitmap());
						//m.setData(b);
						uihandler.sendMessage(m);
					}else{
						Log.d(TAG, "decode fail");
						Message m = uihandler.obtainMessage(MSG_DECODE_FAIL);
						uihandler.sendMessage(m);
					}
				}
				Log.d(TAG, "Processor Done!");
				mProcessor = null;
			}
			
		};
		
		new Thread(mProcessor).start();
		return true;
	}
}
